package nl.unimaas.games.tron.player;

import java.awt.Color;
import java.io.File;

import org.w3c.dom.NamedNodeMap;

import nl.unimaas.games.tron.engine.Board;
import nl.unimaas.games.tron.experiment.GameAnalyzer;
import nl.unimaas.games.tron.experiment.GameAnalyzer.MoveStatistics;
import nl.unimaas.games.tron.player.mcts.Node;
import nl.unimaas.games.tron.player.mcts.SelectionStrategy;

/* UCT enhanced with Progressive Bias */
@SuppressWarnings("serial")
public class BiasedUCTPlayer extends UCTPlayer {
	private final static String DEFAULT_FILE = "data" + File.separator + "movestatistics.dat";
	public final static double DEFAULT_W = 10;
	private MoveStatistics stats;
	
	public BiasedUCTPlayer(String name, int num, Color c) {
		super(name, num, c);
		select = new SelectionStrategy.BiasedUCT(DEFAULT_C, DEFAULT_T, DEFAULT_W);
	}
	
	public void setMoveStatistics(MoveStatistics stats) {
		this.stats = stats;
	}
	
	@Override
	protected Node createNode(int player, Node parent, int move, Board b) {
		Node n = super.createNode(player, parent, move, b);
		if (move != Board.MOVE_NONE) {
			int category = GameAnalyzer.getCategory(b, player, move);
			n.tag = stats.getTransitionalProbability(category);
		}
		return n;
	}
	
	@Override
	public void reset() {
		super.reset();
		if (stats == null) {
			System.err.println("BiasedUCTPlayer doesn't have stats assigned, defaulting to '" + DEFAULT_FILE + "'..");
			try {
				stats = MoveStatistics.fromFile(DEFAULT_FILE);
			}
			catch (Exception e) {
				System.err.println("Unable to load the stats file");
				e.printStackTrace();
			}
		}
	}
	
	@Override
	protected void onComputeFirstMove(Node theRoot) {
		if (stats == null)
			throw new IllegalStateException("I need stats!");
	}
	
	@Override
	protected void onFinishComputation(Node newRoot) {}
	
	public static Player fromXml(org.w3c.dom.Node playerRoot, int num, Color color) {
		return fromXml(playerRoot, new BiasedUCTPlayer(BiasedUCTPlayer.class.getSimpleName(), num, color));
	}
	
	public static Player fromXml(org.w3c.dom.Node playerRoot, BiasedUCTPlayer player) {
		MCTSPlayer.fromXml(playerRoot, player);
		NamedNodeMap attrs = playerRoot.getAttributes();
		double C = DEFAULT_C;
		int T = DEFAULT_T;
		double W = DEFAULT_W;
		String statsFile = DEFAULT_FILE;
		if (attrs.getNamedItem("C") != null) {
			try {
				C = Double.parseDouble(attrs.getNamedItem("C").getNodeValue());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if (attrs.getNamedItem("T") != null) {
			try {
				T = Integer.parseInt(attrs.getNamedItem("T").getNodeValue());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if (attrs.getNamedItem("W") != null) {
			try {
				W = Double.parseDouble(attrs.getNamedItem("W").getNodeValue());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if (attrs.getNamedItem("stats") != null) {
			try {
				statsFile = attrs.getNamedItem("stats").getNodeValue();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		try {
			player.stats = MoveStatistics.fromFile(statsFile);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		player.select = new SelectionStrategy.BiasedUCT(C, T, W);
		player.description = String.format("select=%s playout=%s cut=%s final=%s C=%.1f T=%d W=%.1f stats='%s' expCut=" + player.applyExpansionCutOff + " simCut=" + player.applySimulationCutOff, player.select, player.playout, player.cutOff, player.finalMove, C, T, W, statsFile);
		return player;		
	}
	
	@Override
	public BiasedUCTPlayer clone() {
		BiasedUCTPlayer player = new BiasedUCTPlayer(getName(), getNumber(), getColor());
		player.select = select;
		player.finalMove = finalMove;
		player.cutOff = cutOff;
		player.playout = playout;
		player.description = description;
		player.applyExpansionCutOff = applyExpansionCutOff;
		player.applySimulationCutOff = applySimulationCutOff;
		player.applySpaceEstimation = applySpaceEstimation;
		player.stats = stats;
		return player;
	}
}
